package com.qf.application.commons.aspect;

import com.alibaba.fastjson.JSON;
import com.qf.application.commons.annotation.SysLog;
import com.qf.application.commons.utils.ServletUtils;
import com.qf.application.context.UserContextHolder;
import com.qf.application.entity.SysLogEntity;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@Aspect
@Slf4j
public class SysLogAspect {

    @Pointcut("@annotation(com.qf.application.commons.annotation.SysLog)")
    public void pointcut() {
    }


//    @Before("pointcut()") // 满足条件(目标方法上面加了@SysLog)就会在目标方法之前调用这个方法
//    public void before() {
//        log.debug("在目标方法之前调用");
//    }

//    @Around("pointcut()")
//    public Object around(ProceedingJoinPoint point) throws Throwable {
//        log.debug("环绕通知开始");
//        long starat = System.currentTimeMillis();
//        Object proceed = point.proceed(point.getArgs());
//        log.debug("环绕通知结束");
//        long time = System.currentTimeMillis() - starat;
//        System.out.println("目标方法的耗时:" + (time));
//        return proceed;
//    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        // 1.记录目标方法调用之前的时间
        long starat = System.currentTimeMillis();

        // 2.调用目标方法
        Object proceed = point.proceed(point.getArgs());

        // 3.目标方法的耗时
        long time = System.currentTimeMillis() - starat;

        // 4.目标方法参数
        Object[] args = point.getArgs();

        // 5.如何获取到目标方法上面的@SysLog
        MethodSignature methodSignature = (MethodSignature) point.getSignature(); // 目标方法的签名(方法的定义)
        SysLog sysLog = methodSignature.getMethod().getAnnotation(SysLog.class); // 获取目标方法的@SysLog注解

        String declaringTypeName = methodSignature.getDeclaringTypeName(); // 方法所在的类名
        String methodName = methodSignature.getName(); // 方法名称

        // 6.封装
        SysLogEntity sysLogEntity = new SysLogEntity();
        sysLogEntity.setCreateTime(new Date());
        sysLogEntity.setIp(ServletUtils.getRemoteAddr());
        sysLogEntity.setMethod(declaringTypeName + "." + methodName + "()"); // 目标方法的全类名
        sysLogEntity.setOption(sysLog.value()); // 目标方法上添加@SysLog注解中的value值
        sysLogEntity.setTime(time); // 目标方式执行时间
        sysLogEntity.setUsername(UserContextHolder.get().getUsername()); // 当前登录的用户
        sysLogEntity.setParams(JSON.toJSONString(args)); // 目标方法的参数


        // 7、把sysLogEntity保存到数据库中
        saveSysLog(sysLogEntity);


        return proceed;
    }

    private void saveSysLog(SysLogEntity sysLogEntity) {
        log.debug("{}", sysLogEntity);
    }
}
